// index.js https://github.com/wechat-miniprogram/markdown-latex-demo
const testStr = `1. **泰勒展开展开**：
   我们可以分别写出指数函数 \( e^{ix} \)、余弦函数 \( \cos x \) 和正弦函数 \( \sin x \) 的泰勒展开式。
   - 指数函数 \( e^{ix} \) 的泰勒展开式为：
     \[
     e^{ix} = 1 + ix + \\frac{(ix)^2}{2!} + \\frac{(ix)^3}{3!} + \\frac{(ix)^4}{4!} + \\cdots
     \]

   - 余弦函数 \( \cos x \) 的泰勒展开式为：
     \[
     \\cos x = 1 - \\frac{x^2}{2!} + \\frac{x^4}{4!} - \\frac{x^6}{6!} + \\cdots
     \]

   - 正弦函数 \( \sin x \) 的泰勒展开式为：
     \[
     \\sin x = x - \\frac{x^3}{3!} + \\frac{x^5}{5!} - \\frac{x^7}{7!} + \\cdots
     \]

2. **计算 \( e^{ix} \) 的展开式**：
   将 \( e^{ix} \) 的展开式中的每一项中的 \( ix \) 展开：

   \[
   e^{ix} = 1 + ix + \\frac{(ix)^2}{2!} + \\frac{(ix)^3}{3!} + \\frac{(ix)^4}{4!} + \\cdots
   \]

   计算每一项：

   - \( (ix)^1 = ix \)
   - \( (ix)^2 = i^2 x^2 = -x^2 \)
   - \( (ix)^3 = i^3 x^3 = -i x^3 \)
   - \( (ix)^4 = i^4 x^4 = x^4 \)
   - \( (ix)^5 = i^5 x^5 = i x^5 \)
   - 依此类推。

   因此，\( e^{ix} \) 可以展开为：
   \[
   e^{ix} = 1 + ix - \\frac{x^2}{2!} - i\\frac{x^3}{3!} + \\frac{x^4}{4!} + i\\frac{x^5}{5!} - \\cdots
   \]
`;

const testStr_old = `1. **泰勒展开展开**：
   我们可以分别写出指数函数 \( e^{ix} \)、余弦函数 \( \cos x \) 和正弦函数 \( \sin x \) 的泰勒展开式。
   - 指数函数 \( e^{ix} \) 的泰勒展开式为：
     \[
     e^{ix} = 1 + ix + \frac{(ix)^2}{2!} + \frac{(ix)^3}{3!} + \frac{(ix)^4}{4!} + \cdots
     \]

   - 余弦函数 \( \cos x \) 的泰勒展开式为：
     \[
     \cos x = 1 - \frac{x^2}{2!} + \frac{x^4}{4!} - \frac{x^6}{6!} + \cdots
     \]

   - 正弦函数 \( \sin x \) 的泰勒展开式为：
     \[
     \sin x = x - \frac{x^3}{3!} + \frac{x^5}{5!} - \frac{x^7}{7!} + \cdots
     \]

2. **计算 \( e^{ix} \) 的展开式**：
   将 \( e^{ix} \) 的展开式中的每一项中的 \( ix \) 展开：

   \[
   e^{ix} = 1 + ix + \frac{(ix)^2}{2!} + \frac{(ix)^3}{3!} + \frac{(ix)^4}{4!} + \cdots
   \]

   计算每一项：

   - \( (ix)^1 = ix \)
   - \( (ix)^2 = i^2 x^2 = -x^2 \)
   - \( (ix)^3 = i^3 x^3 = -i x^3 \)
   - \( (ix)^4 = i^4 x^4 = x^4 \)
   - \( (ix)^5 = i^5 x^5 = i x^5 \)
   - 依此类推。

   因此，\( e^{ix} \) 可以展开为：
   \[
   e^{ix} = 1 + ix - \frac{x^2}{2!} - i\frac{x^3}{3!} + \frac{x^4}{4!} + i\frac{x^5}{5!} - \cdots
   \]
`;

function replaceBracketsWithDollars(text) {
  // 正则表达式：匹配所有被 [ 和 ] 包裹的内容
  const regex = /\[([^\]]+)\]/g;
  // 使用 replace 方法进行替换
  return text.replace(regex, (match, formula) => {
    // 判断公式是否包含换行符，如果包含则使用 $$ 包裹，否则使用 $ 包裹
    if (formula.includes('\n')) {
      return `$$${formula}$$`;
    }
    return `$${formula}$`;
  });
}



const systemInfo = wx.getDeviceInfo();
const screenWidth = systemInfo.screenWidth;
const app=getApp();
const response_max_tokens = 4096;
import parse from "@rojer/katex-mini";
import katex from "katex";

function processBlockFormulas(markdownWithLaTeX) {
  const combinedNodes = [];
  const regexBlock = /\\\[([^\]]+)\\\]/gs;
  const blockFormulaRegex = /\$\$([^$]*?)\$\$/gs;
  let lastIndex = 0;
  let blockMatch;
  let blockMatch_1;
  let blockMatch_2;
  while ( (blockMatch_1 = blockFormulaRegex.exec(markdownWithLaTeX))!== null||
        (blockMatch_2 = regexBlock.exec(markdownWithLaTeX))!== null ) {
          if(blockMatch_1){
            blockMatch = blockMatch_1;
          }else if(blockMatch_2){
            blockMatch = blockMatch_2;
          }
      // 处理块级公式前的文本
      const beforeBlock = markdownWithLaTeX.slice(lastIndex, blockMatch.index);
      if (beforeBlock) {
          const nodesBeforeBlock = processInlineFormulas(beforeBlock);
          combinedNodes.push(...nodesBeforeBlock);
      }

      // 处理块级公式
      const blockFormula = blockMatch[1];
      try {
          const katexOption = {
            displayMode: true,
          }; // 参考 katex 的配置
          const renderedBlockFormula = parse(blockFormula,{
            throwError: true, // 为true时，解析失败会抛出错误，否则会直接把错误信息解析为nodes结构展示
            ...katexOption,
          });
          combinedNodes.push(renderedBlockFormula);
          //console.log('renderedBlockFormula 类型:', typeof renderedBlockFormula);
          //console.log('renderedBlockFormula 内容:', renderedBlockFormula);
      } catch (error) {
          console.error('LaTeX 块级公式解析错误:', error);
      }
      if(blockMatch_1){
        lastIndex = blockFormulaRegex.lastIndex;
      }else if(blockMatch_2){
        lastIndex = regexBlock.lastIndex;
      }
  }
  // 处理最后一个块级公式之后的文本
  const remainingAfterLastBlock = markdownWithLaTeX.slice(lastIndex);
  if (remainingAfterLastBlock) {
      const nodesAfterLastBlock = processInlineFormulas(remainingAfterLastBlock);
      combinedNodes.push(...nodesAfterLastBlock);
  }
  return combinedNodes;
}
// 处理行内公式和普通 Markdown 文本
function processInlineFormulas(text) {
  const combinedNodes = [];
  const regexInline = /\\\(([^()]*(\([^()]*\)[^()]*)*)\\\)/g;
  const inlineFormulaRegex = /\$([^$]*?)\$/g;
  let lastIndex = 0;
  let match_1;
  let match_2;
  let match;
  while ((match_1 = inlineFormulaRegex.exec(text))!== null||
        (match_2 = regexInline.exec(text))!== null) {
          if(match_1){
            match = match_1;
          }else if(match_2){
            match = match_2;
          }
      // 处理行内公式前的文本
      const before = text.slice(lastIndex, match.index);
      if (before) {
          const towxmlPart = app.towxml(before, 'markdown', {
              theme: 'light'
          });
          combinedNodes.push(towxmlPart);
          //let cleanTowxmlPart = towxmlPart.replace(/\s+/g, ' ').trim();
          //combinedNodes.push(cleanTowxmlPart);
          console.log('beforeInline:towxmlPart 类型:', typeof towxmlPart);
          console.log('beforeInline:towxmlPart 内容:', towxmlPart);
      }

      // 处理行内公式
      const formula = match[1];
      try {
          //const renderedFormula =  parse(formula);
          const katexOption = {
            displayMode: true,
          }; // 参考 katex 的配置
          const renderedFormula = parse(formula,{
            throwError: true, // 为true时，解析失败会抛出错误，否则会直接把错误信息解析为nodes结构展示
            ...katexOption,
          });
          combinedNodes.push(renderedFormula); 
          //let cleanRenderedFormula = renderedFormula.replace(/\s+/g, ' ').trim();
          //combinedNodes.push(cleanRenderedFormula);          
          //console.log('renderedFormula 类型:', typeof renderedFormula);
          //console.log('renderedFormula 内容:', renderedFormula);
      } catch (error) {
          console.error('LaTeX 行内公式解析错误:', error);
      }
      if(match_1){
        lastIndex = inlineFormulaRegex.lastIndex;
      }else if(match_2){
        lastIndex = regexInline.lastIndex;
      }
  }

  // 处理行内公式处理完后剩余的文本
  const remaining = text.slice(lastIndex);
  if (remaining) {
      let towxmlPart = app.towxml(remaining, 'markdown', {
          theme: 'light'
      });
      //let cleanTowxmlPart = towxmlPart.replace(/\s+/g, ' ').trim();
      //combinedNodes.push(cleanTowxmlPart);
      combinedNodes.push(towxmlPart);
      console.log('remaining:towxmlPart 类型:', typeof towxmlPart);
      console.log('remaining:towxmlPart 内容:', towxmlPart);
  }
  return combinedNodes;
}

Page({
  data: {
    /*
    models: ['deepseek-ai/DeepSeek-R1','deepseek-ai/DeepSeek-V3','deepseek-ai/DeepSeek-R1-Distill-Llama-70B','deepseek-ai/DeepSeek-R1-Distill-Qwen-32B','deepseek-ai/DeepSeek-R1-Distill-Qwen-14B','deepseek-ai/DeepSeek-R1-Distill-Llama-8B','deepseek-ai/DeepSeek-R1-Distill-Qwen-7B','deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B','Pro/deepseek-ai/DeepSeek-R1-Distill-Llama-8B','Pro/deepseek-ai/DeepSeek-R1-Distill-Qwen-7B','Pro/deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B'], // 支持的模型列表
    */
    models: [
      { name: '深探-R1(推理模型，适合广泛任务)', value: 'deepseek-ai/DeepSeek-R1' },
      { name: '深探-V3(对话模型，高性能版本，适合复杂问题)', value: 'deepseek-ai/DeepSeek-V3' },
      { name: '深探-智简70(精简高效，适合快速处理简单问题)', value: 'deepseek-ai/DeepSeek-R1-Distill-Llama-70B' },
      { name: '深探-智简32(中等规模，适合平衡性能与效率)', value: 'deepseek-ai/DeepSeek-R1-Distill-Qwen-32B' },
      { name: '深探-智简14(轻量级，适合日常任务)', value: 'deepseek-ai/DeepSeek-R1-Distill-Qwen-14B' },
      { name: '深探-智简8(小巧灵活，适合快速响应)', value: 'deepseek-ai/DeepSeek-R1-Distill-Llama-8B' },
      { name: '深探-智简7(轻量高效，适合基础任务)', value: 'deepseek-ai/DeepSeek-R1-Distill-Qwen-7B' },
      { name: '深探-智简1.5(极简设计，适合低资源环境)', value: 'deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B' },
      { name: '深探-Pro智简8(专业版，适合高效处理简单问题)', value: 'Pro/deepseek-ai/DeepSeek-R1-Distill-Llama-8B' },
      { name: '深探-Pro智简7(专业版，适合轻量级专业任务)', value: 'Pro/deepseek-ai/DeepSeek-R1-Distill-Qwen-7B' },
      { name: '深探-Pro智简1.5(专业版，适合极简环境下的快速响应)', value: 'Pro/deepseek-ai/DeepSeek-R1-Distill-Qwen-1.5B' },
      { name: '灵犀-70(高精度，适合复杂指令任务)', value: 'meta-llama/Llama-3.3-70B-Instruct' },
      { name: '马可-o1(多功能，适合多样化任务)', value: 'AIDC-AI/Marco-o1' },
      { name: '深探-V2.5(稳定版，适合常规任务)', value: 'deepseek-ai/DeepSeek-V2.5' },
      { name: '千问-72(大规模，适合高复杂度问题)', value: 'Qwen/Qwen2.5-72B-Instruct-128K' },
      { name: '千问-智简72(高性能，适合复杂指令)', value: 'Qwen/Qwen2.5-72B-Instruct' },
      { name: '千问-智简32(中等规模，适合平衡性能)', value: 'Qwen/Qwen2.5-32B-Instruct' },
      { name: '千问-智简14(轻量级，适合日常指令任务)', value: 'Qwen/Qwen2.5-14B-Instruct' },
      { name: '千问-智简7(小巧灵活，适合快速响应)', value: 'Qwen/Qwen2.5-7B-Instruct' },
      { name: '千问-编程32(专为编程设计，适合代码生成)', value: 'Qwen/Qwen2.5-Coder-32B-Instruct' },
      { name: '千问-编程7(轻量级编程助手，适合基础代码任务)', value: 'Qwen/Qwen2.5-Coder-7B-Instruct' },
      { name: '千问-智简7(轻量高效，适合日常任务)', value: 'Qwen/Qwen2-7B-Instruct' },
      { name: '千问-智简1.5(极简设计，适合低资源环境)', value: 'Qwen/Qwen2-1.5B-Instruct' },
      { name: '千问-预览32(预览版，适合测试新功能)', value: 'Qwen/QwQ-32B-Preview' },
      { name: 'TeleChat2(适合聊天场景，交互性强)', value: 'TeleAI/TeleChat2' },
      { name: 'Yi-智简34(高性能，适合长文本对话)', value: '01-ai/Yi-1.5-34B-Chat-16K' },
      { name: 'Yi-智简9(中等规模，适合平衡性能与效率)', value: '01-ai/Yi-1.5-9B-Chat-16K' },
      { name: 'Yi-智简6(轻量级，适合日常对话)', value: '01-ai/Yi-1.5-6B-Chat' },
      { name: '智语-4(适合聊天场景，交互性强)', value: 'THUDM/glm-4-9b-chat' },
      { name: '千问-智简72(高性能，适合复杂指令)', value: 'Vendor-A/Qwen/Qwen2.5-72B-Instruct' },
      { name: 'InternLM-智简7(轻量级，适合日常任务)', value: 'internlm/internlm2_5-7b-chat' },
      { name: 'InternLM-智简20(中等规模，适合平衡性能)', value: 'internlm/internlm2_5-20b-chat' },
      { name: '灵犀-70(高精度，适合复杂指令任务)', value: 'nvidia/Llama-3.1-Nemotron-70B-Instruct' },
      { name: 'Meta-灵犀405(超大规模，适合超高复杂度问题)', value: 'meta-llama/Meta-Llama-3.1-405B-Instruct' },
      { name: 'Meta-灵犀70(高性能，适合复杂指令)', value: 'meta-llama/Meta-Llama-3.1-70B-Instruct' },
      { name: 'Meta-灵犀8(小巧灵活，适合快速响应)', value: 'meta-llama/Meta-Llama-3.1-8B-Instruct' },
      { name: 'Gemma-27(高性能，适合多样化任务)', value: 'google/gemma-2-27b-it' },
      { name: 'Gemma-9(轻量级，适合基础任务)', value: 'google/gemma-2-9b-it' },
      { name: '千问-Pro智简7(专业版，适合高效处理简单问题)', value: 'Pro/Qwen/Qwen2.5-7B-Instruct' },
      { name: '千问-Pro智简7(专业版，适合轻量级专业任务)', value: 'Pro/Qwen/Qwen2-7B-Instruct' },
      { name: '千问-Pro智简1.5(专业版，适合极简环境下的快速响应)', value: 'Pro/Qwen/Qwen2-1.5B-Instruct' },
      { name: '智语-Pro6(专业版，适合高效聊天场景)', value: 'Pro/THUDM/chatglm3-6b' },
      { name: '智语-Pro4(专业版，适合高性能聊天场景)', value: 'Pro/THUDM/glm-4-9b-chat' },
      { name: 'Meta-Pro灵犀8(专业版，适合快速响应)', value: 'Pro/meta-llama/Meta-Llama-3.1-8B-Instruct' },
      { name: 'Gemma-Pro9(专业版，适合轻量级任务)', value: 'Pro/google/gemma-2-9b-it' }
    ],
    modelsNames: [], // 新增 modelsNames 数组
    screenWidth: screenWidth,
    selectedModel: '', // 当前选择的模型
    selectedModelIndex:0,
    question: '', // 用户输入的问题    
    questionIndex: 0, //问题索引；
    result: [], // 改为数组存储分片结果
    chunks: [], // 新增分片内容存储
    isLoading: false, // 新增加载状态
    shouldStop: false, //用来控制是否停止回答；
    fullAnswer: '', // 新增完整回答存储
    finalAnswer: '', //最终获得的回答
    formulas: [
      "e^{ix} = 1 + ix + \\frac{(ix)^2}{2!} + \\frac{(ix)^3}{3!} + \\frac{(ix)^4}{4!} + \\cdots",
      "\\cos x = 1 - \\frac{x^2}{2!} + \\frac{x^4}{4!} - \\frac{x^6}{6!} + \\cdots",
      "\\sin x = x - \\frac{x^3}{3!} + \\frac{x^5}{5!} - \\frac{x^7}{7!} + \\cdots",
      "e^{ix} = 1 + ix - \\frac{x^2}{2!} - i\\frac{x^3}{3!} + \\frac{x^4}{4!} + i\\frac{x^5}{5!} - \\cdots",
    ],
    //formula:"e^{ix} = 1 + ix + \\frac{(ix)^2}{2!} + \\frac{(ix)^3}{3!} + \\frac{(ix)^4}{4!} + \\cdots",
    //formula: "e^{ix} = \\cos(x) + i \\sin(x)", 
    //formula:'  \\displaystyle \\frac{1}{\\Bigl(\\sqrt{\\phi \\sqrt{5}}-\\phi\\Bigr) e^{\\frac25 \\pi}} = 1+\\frac{e^{-2\\pi}} {1+\\frac{e^{-4\\pi}} {1+\\frac{e^{-6\\pi}} {1+\\frac{e^{-8\\pi}} {1+\\cdots} } } } ',    
    formula:`[
      e^{ix} = 1 + ix - \\frac{x^2}{2!} - i\\frac{x^3}{3!} + \\frac{x^4}{4!} + i\\frac{x^5}{5!} - \\cdots
    ]`,
    renderedFormula:"",
    renderedFormulas: [],
    combinedNodesForDisp:[]
  },

  navigateToSettings(){
    wx.navigateTo({
      url: '/pages/setting/setting',
    })
  },
  onLoad() {
    // 从本地存储中读取默认模型
    const selectedModel = wx.getStorageSync('selectedModel') || this.data.models[0].value;
    this.setData({
      selectedModel: selectedModel,
      modelsNames: this.data.models.map(model => model.name)
    });    
    //this.renderFormula();  
    //this. pMixContent2();
    //this.processMixedContent(testStr);  
  },

  processMixedContent(markdownWithLaTeX) {
    //const markdownWithLaTeX = testStr; // this.data;
    console.log('markdownWithLaTeX', markdownWithLaTeX);
    const combinedNodes = processBlockFormulas(markdownWithLaTeX);
    this.setData({
        combinedNodesForDisp: combinedNodes
    });
  },

  renderFormula() {    
    const renderedFormula = katex.renderToString(this.data.formula, {
      throwOnError: false,
    });    
    //console.log('renderedFormula',renderedFormula);       
    const nodes = parse(this.data.formula);
    console.log('nodes',nodes);    
    const towxmlData=app.towxml(renderedFormula,'html',{
      theme:'light',      
      math:true,
      katex:true
    });
    
    this.setData({      
      result:this.data.result.concat(towxmlData),
      renderedFormulas:nodes,      
    });
  },

  onModelChange(e) {
    const selectedModelIndex = e.detail.value;
    const selectedModel = this.data.models[selectedModelIndex].value;        
    this.setData({ 
      selectedModel: selectedModel, 
      selectedModelIndex: selectedModelIndex 
    });
    wx.setStorageSync('selectedModel', selectedModel);
  },

  onInput(e) {
    this.setData({
      question: e.detail.value
    });
  },

  askQuestion() {
      const apiKey = wx.getStorageSync('apiKey');
      const selectedModel = this.data.selectedModel;
      const question = this.data.question;     
     // const preQuestionIndex = this.data.questionIndex;
      const curQuestionIndex = this.data.questionIndex+1;
  
      if (!question) {
        wx.showToast({
          title: '问题不能为空',
          icon: 'none'
        });
        return;
      }

      this.setData({
        result: [],
        fullAnswer: '',
        finalAnswer:'',
        isLoading: true,
        shouldStop: false,
        combinedNodesForDisp:[],
        questionIndex:curQuestionIndex
      });
  
      const that = this;
      const messages = [
        { role: 'system', content: '你是一位很有帮助的助手，请用中文回答提问。'},//，如果回答被截断，请在截断处用\'+-*/\'标记' },
        { role: 'user', content: question }
      ];
      /*
      this.setData({
        fullAnswer:'你已经开始回答这个问题:'+question+"。你的回答是这样的："
      })
      */
      // 首次请求
      wx.request({
        url: 'https://api.siliconflow.cn/v1/chat/completions',
        method: 'POST',
        header: {
          'Authorization': `Bearer ${apiKey}`,
          'Content-Type': 'application/json'
        },
        data: {
          model: selectedModel,
          messages: messages,
          temperature: 0.7,
          max_tokens: response_max_tokens // 尽量获取最大长度
        },
        success: function(res) {
          if (res.data.choices?.[0] && 
              that.data.shouldStop==false && 
              that.data.questionIndex == curQuestionIndex) {
            wx.hideLoading();
            const fullAnswer = res.data.choices[0].message.content;
            console.log('direct Answer from AI model:',fullAnswer);
            //that.processLongAnswer(fullAnswer, res.data.choices[0].finish_reason);
            let finalAnswer = fullAnswer;
            if(res.data.choices[0].finish_reason=='stop'){
               finalAnswer +='\n回答完毕\n\n';
            }else{
               finalAnswer +='\n note:由于最大输出数量限制，答案没有完整输出\n\n';
            }
            that.setData({
              finalAnswer:finalAnswer
            })            
            that.processMixedContent(finalAnswer);
          }
        },
        fail: function(err) {
          if(that.data.shouldStop==false && 
            that.data.questionIndex == curQuestionIndex){
            wx.hideLoading();
            wx.showToast({ title: '请求失败', icon: 'none' });
            that.setData({ isLoading: false });
          }
        }
      });    
      wx.showLoading({
        title: '思考中...',
      }); 
    },
  
    // 长文本处理核心方法
    processLongAnswer(answer, finishReason) {
      const chunks = this.splitAnswer(answer);
      const processedChunks = chunks.map(chunk => {
        const processed = chunk;//replaceBracketsWithDollars(chunk);
        return app.towxml(processed, 'markdown', {
          theme: 'light',
          math: true          
        });
      });
      this.setData({
        fullAnswer: this.data.fullAnswer + answer,
        result: this.data.result.concat(processedChunks)
      });
      
      //console.log('finishReason',finishReason); 
      //if(finishReason=='length'){
      //  console.log('fullAnswer',this.data.fullAnswer);
      //};
      // 判断是否需要续写
      if (finishReason === 'length' && !this.data.shouldStop) {
       //this.requestContinuation();
      } else {
        this.setData({ isLoading: false });
      }
    },
  
    // 智能分块算法
    splitAnswer(answer) {
      const SPLIT_MARKS = ['\n\n', '。', '；', '!', '?', '】']; // 优先在这些符号后切分
      const MAX_CHUNK = 500; // 每个分块最大长度
      
      let chunks = [];
      let start = 0;
  
      while (start < answer.length) {
        let end = Math.min(start + MAX_CHUNK, answer.length);
        // 寻找最佳分割点
        for (const mark of SPLIT_MARKS) {
          const pos = answer.lastIndexOf(mark, end);
          if (pos > start + MAX_CHUNK*0.8) { // 避免切分过小片段
            end = pos + mark.length;
            break;
          }
        }
        chunks.push(answer.slice(start, end));
        start = end;
      }
      return chunks;
    },
  
    // 续写请求
    requestContinuation() {
      const apiKey = wx.getStorageSync('apiKey');
      const selectedModel = this.data.selectedModel;
      const question = this.data.question;
      const messages = [
        { role: 'system', content: this.data.fullAnswer },
        { role: 'user', content: '请从\'+-*/\'标记处继续完成回答' }
      ];
  
      wx.request({
        url: 'https://api.siliconflow.cn/v1/chat/completions',
        method: 'POST',
        header: {
          'Authorization': `Bearer ${apiKey}`,
          'Content-Type': 'application/json'
        },
        data: {
          model: this.data.selectedModel,
          messages: messages,
          temperature: 0.7,
          max_tokens: response_max_tokens
        },
        success: (res) => {          
          if (res.data.choices?.[0]) {
            const newPart = res.data.choices[0].message.content;
            this.processLongAnswer(newPart, res.data.choices[0].finish_reason);
          }
        },
        fail: function(err) {
          wx.showToast({ title: '请求失败', icon: 'none' });
          that.setData({ isLoading: false });
        }
      });
    },

  copyAnswer(){
    wx.setClipboardData({
      data: this.data.finalAnswer,
      success(){
        wx.showToast({
          title: '回答已拷贝',
        });
        console.log('答案已拷贝');
      }
    });
  },

  stopAnswering() {
    wx.hideLoading();
    this.setData({ shouldStop: true });
  }
});
   


/*
  askQuestion() {
    const apiKey = wx.getStorageSync('apiKey');
    const selectedModel = this.data.selectedModel;
    const question = this.data.question;    
    const faqQuestion = "由于max_tokens限制，上个问题可能没有回答完；如果没有回答完，那么请将答案补充完整，回答完就算了。上个问题是："+question;
    this.setData({
      result: [],
      chunks: [],
      isLoading:true,
      shouldStop: false
    });
    if (!question) {
      wx.showToast({
        title: '问题不能为空',
        icon: 'none'
      });
      return;
    }
    //分片处理，调用api:
    let resultStr = '';
    const that = this;
    const response_max_tokens = 1024;
    function fetchData(questionStr, offset = 0) {
      if(that.data.shouldStop){
        that.setData({isLoading:false});
        return;
      }
      wx.request({
      url: 'https://api.siliconflow.cn/v1/chat/completions',
      method: 'POST',
     header: {
       'Authorization': `Bearer ${apiKey}`,
       'Content-Type': 'application/json'
     },
      data: {
        model: selectedModel,
        messages: [        
            { role: 'system', content: 'You are a helpful assistant.' },
            { role: 'user', content: questionStr}        
        ],
        n:2,
        temperature: 0.7,
        max_tokens: response_max_tokens, // 每次请求的最大 token 数量
        offset: offset // 分片偏移量
     },
    success: (res) => {
      // 分片处理核心逻辑
      if (res.data.choices && res.data.choices[0]) {
        const chunk = res.data.choices[0].message.content;        
        // 1. 存储原始分片
        that.data.chunks.push(chunk);        
        // 2. 预处理当前分片
        console.log('chunk:',chunk);
        const processedChunk = preprocessText(chunk);     
        //const processedChunk = replaceBracketsWithDollars(chunk);
        console.log('processedChunk:',processedChunk);   
        // 3. 解析为towxml对象
        let obj = app.towxml(processedChunk, 'markdown', {
          theme: 'light',
          math: true, // 启用数学公式支持
          events: {
            tap: e => console.log('tap', e),
            change: e => console.log('todo', e)
          }
        });
        // 4. 更新结果数组
        that.setData({
          result: [...that.data.result, obj]
        });
        // 5. 判断是否继续请求（若停止提问，则直接退出，避免不停输出问题的答案）
        if(that.data.shouldStop){
          that.setData({isLoading:false});
          return;
        }
        if (res.data.choices[0].finish_reason === 'length') {
          offset += response_max_tokens;                    
          fetchData(faqQuestion);
        } else {
          that.setData({ isLoading: false });
        }
      }
    },
    fail: (err) => {
      wx.showToast({ title: '网络错误', icon: 'none' });
      console.error('请求失败：', err);
      that.setData({ isLoading: false });
    }
  });
}
     fetchData(question);
  },
  stopAnswering(){
    this.setData({
      shouldStop:true
    })
  }
  */